导 读
本文主要介绍在C#中使用YOLOv11实现实例分割,并给详细步骤和源码。
C# YOLO11实例分割——本文实现效果:
实现步骤
关于YOLO11和YoloSharp的介绍请参考下面两篇文章,有详细步骤:
实战 | C#中使用YoloV8和OpenCvSharp实现目标检测 (步骤 + 源码)_yolosharp-CSDN博客
实战 | C# 中使用YOLOv11实现目标检测 (步骤 + 源码)_c# yolo-CSDN博客
检测模型可以试下载官方模型,也可以使用自己训练的模型,本文使用yolo11n-seg.pt,然后转换为onnx模型yolo11n-seg.onnx,转换代码如下:
from ultralytics import YOLO
# Load a model
model = YOLO("yolo11n-seg.pt") # load an official model
# Export the model
model.export(format="onnx")
注意安装ultralytics最新版本,避免模型转换失败!
代码部分,没有UI的代码和目标检测部分基本一致,主要是这句
var results = predictor.Segment(srcImg.ToMemoryStream());
其中原来的Detect变成了Segment,检测变分割,使用下面代码保存得到官方的结果图
using var image = SixLabors.ImageSharp.Image.Load(pathList[imgIndex]);
using var ploted = results.PlotImage(image);
ploted.Save("cc.jpg");
后面改成了WinForm版本,绘制时需要获取掩码(mask)自行绘制,这部分核心代码在ImgSegment函数中:
public Mat ImgSegment(Mat srcImg)
{
Mat img = srcImg.Clone();
//Mat img = Mat.Zeros(srcImg.Size(), MatType.CV_8UC3);
var results = predictor.Segment(srcImg.ToMemoryStream());
for (int index = 0; index < results.Count; index++)
{
Cv2.Rectangle(img, new OpenCvSharp.Point(results[index].Bounds.Left, results[index].Bounds.Top), new OpenCvSharp.Point(results[index].Bounds.Right, results[index].Bounds.Bottom), new Scalar(255, 0, 255), 2);
string text = results[index].Name.Name + ":" + results[index].Confidence.ToString("F2");
Cv2.PutText(img, text, new OpenCvSharp.Point(results[index].Bounds.Left, results[index].Bounds.Top + 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 255, 0), 2);
//用At方法访问像素值
int x0 = results[index].Bounds.X;
int y0 = results[index].Bounds.Y;
for (int i = 0; i < results[index].Mask.Height; i++)
{
for (int j = 0; j < results[index].Mask.Width; j++)
{
if (results[index].Mask[i, j] > 0.5)
img.At<Vec3b>(i + y0, j + x0) = colors[index % 6]; //RGB彩色图像素值改变
}
}
}
//using var image = SixLabors.ImageSharp.Image.Load(pathList[imgIndex]);
//using var ploted = results.PlotImage(image);
//ploted.Save("cc.jpg");
return img;
}
然后最终效果如下:
完整代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Compunet.YoloSharp;
using Compunet.YoloSharp.Plotting;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using SixLabors.ImageSharp;
namespace YoloSharp_Segment
{
public partial class Form1 : Form
{
//Mat srcImg = new Mat();
static YoloPredictor predictor = new YoloPredictor("yolo11n-seg.onnx");
string[] pathList;
Vec3b[] colors = {new Vec3b(0, 255, 0), new Vec3b(0, 0, 255), new Vec3b(255, 0, 0),
new Vec3b(0, 255, 255), new Vec3b(255, 255, 0), new Vec3b(255, 0, 255) };
int imgIndex = 0;
public Form1()
{
InitializeComponent();
predictor.Configuration.SuppressParallelInference = true;
predictor.Configuration.KeepAspectRatio = true;
predictor.Configuration.Confidence = 0.3F;
}
public Mat ImgSegment(Mat srcImg)
{
Mat img = srcImg.Clone();
//Mat img = Mat.Zeros(srcImg.Size(), MatType.CV_8UC3);
var results = predictor.Segment(srcImg.ToMemoryStream());
for (int index = 0; index < results.Count; index++)
{
Cv2.Rectangle(img, new OpenCvSharp.Point(results[index].Bounds.Left, results[index].Bounds.Top), new OpenCvSharp.Point(results[index].Bounds.Right, results[index].Bounds.Bottom), new Scalar(255, 0, 255), 2);
string text = results[index].Name.Name + ":" + results[index].Confidence.ToString("F2");
Cv2.PutText(img, text, new OpenCvSharp.Point(results[index].Bounds.Left, results[index].Bounds.Top + 30), HersheyFonts.HersheyComplex, 1, new Scalar(0, 255, 0), 2);
//用At方法访问像素值
int x0 = results[index].Bounds.X;
int y0 = results[index].Bounds.Y;
for (int i = 0; i < results[index].Mask.Height; i++)
{
for (int j = 0; j < results[index].Mask.Width; j++)
{
if (results[index].Mask[i, j] > 0.5)
img.At<Vec3b>(i + y0, j + x0) = colors[index % 6]; //RGB彩色图像素值改变
}
}
}
//using var image = SixLabors.ImageSharp.Image.Load(pathList[imgIndex]);
//using var ploted = results.PlotImage(image);
//ploted.Save("cc.jpg");
return img;
}
private void buttonOpenFolder_Click(object sender, EventArgs e)
{
//OpenFileDialog ofd = new OpenFileDialog(); //创建打开对话框对象
//ofd.Title = "请选择打开的文件"; //设置对话框标题
//ofd.Multiselect = true; //设置文件是否可以多选
//ofd.InitialDirectory = @"./"; //设置初始打开目录
////文本文件(*.txt) | *.txt | 所有文件(*.*) | *.*””
//ofd.Filter = "图片文件|*.jpg;*.png;*.bmp;*.jpeg"; //打开jpg图片文件和png 图片文件
//ofd.ShowDialog(); //显示对话框
//string path = ofd.FileName; // 选择文件的全路径
//if (path == "") //异常处理,点击取消时,空路径报错
//{
// return;
//}
////显示打开图片
//srcImg = Cv2.ImRead(path);
//pictureBoxSrc.Image = srcImg.ToBitmap();
//if(pathList.Length > 0)
// Array.Clear(pathList, 0, pathList.Length);
using (FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog())
{
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{
string folderPath = folderBrowserDialog.SelectedPath;
pathList = Directory.GetFiles(folderPath, "*.*")
.Where(file => file.EndsWith(".jpg") || file.EndsWith(".png") || file.EndsWith(".bmp"))
.ToArray();
}
}
if (pathList.Length == 0)
return;
imgIndex = 0;
Mat img = Cv2.ImRead(pathList[0]);
pictureBoxSrc.Image = img.ToBitmap();
Mat resImg = ImgSegment(img);
pictureBoxResult.Image = resImg.ToBitmap();
}
private void buttonPreOne_Click(object sender, EventArgs e)
{
if (imgIndex == 0)
imgIndex = 0;
else
{
imgIndex--;
}
Mat img = Cv2.ImRead(pathList[imgIndex]);
pictureBoxSrc.Image = img.ToBitmap();
Mat resImg = ImgSegment(img);
pictureBoxResult.Image = resImg.ToBitmap();
}
private void buttonNextOne_Click(object sender, EventArgs e)
{
if (imgIndex == pathList.Length-1)
imgIndex = pathList.Length - 1;
else
{
imgIndex++;
}
Mat img = Cv2.ImRead(pathList[imgIndex]);
pictureBoxSrc.Image = img.ToBitmap();
Mat resImg = ImgSegment(img);
pictureBoxResult.Image = resImg.ToBitmap();
}
}
}